ANDROID COMPONENTS

BROADCAST RECEIVER EXPLAINED

The invisible messenger of Android. Intercept system-wide events, respond to app signals, and build reactive applications with one of Android's most powerful components.

android.content.BroadcastReceiver Intent-based Event-driven
SCROLL

What is a
Broadcast Receiver?

A Broadcast Receiver is an Android component that allows your application to subscribe to system-wide or app-level events. Think of it as a radio tuner — it listens on specific channels and reacts when a signal arrives.

When something significant happens — the battery gets low, Wi-Fi connects, an SMS arrives, or even when your own app wants to signal other parts of itself — Android sends out a broadcast Intent. Any registered receiver tuned to that frequency wakes up and responds.

Receivers work even when your app isn't in the foreground, making them ideal for background reactions to real-world events — without keeping your app alive unnecessarily.

SIGNAL FLOW
📱 App / System
⚡ Intent
🤖 Android OS
📡 Your Receiver
broadcast signal propagating →

How does it work?

01

An event occurs

Something triggers a broadcast — the system boots, a network changes, a call comes in, or your app fires a custom event. This is the spark that starts the chain.

TRIGGER
02

An Intent is packaged

The broadcaster creates an Intent object with an action string (like ACTION_BATTERY_LOW) and optional extras — data that travels with the signal.

INTENT CREATION
03

Android routes the broadcast

The OS checks all registered receivers — both those declared in AndroidManifest.xml and those registered dynamically — to find matching IntentFilters.

ROUTING
04

onReceive() is called

Your receiver's onReceive(Context, Intent) method fires on the main thread. You have a strict 10-second window to complete work — for longer tasks, delegate to a Service or WorkManager.

EXECUTION

Types of Broadcasts

🌐

Normal Broadcast

Delivered to all receivers asynchronously and in an undefined order. Most efficient type — all receivers get the broadcast roughly simultaneously with no defined priority.

sendBroadcast()
📋

Ordered Broadcast

Delivered to receivers one at a time based on priority. Each receiver can propagate or abort the broadcast before the next receiver sees it. Useful for interception patterns.

sendOrderedBroadcast()
🔒

Local Broadcast

Stays within your app's process using LocalBroadcastManager. More efficient and secure — data never leaves your app. Ideal for in-app communication.

LocalBroadcastManager
📌

Sticky Broadcast (Deprecated in API 21)

Broadcasts that stay in the system after being sent. When a new receiver registered, it immediately receives the last sticky broadcast for that action. Replaced by explicit data stores like SharedPreferences or ViewModel.

sendStickyBroadcast()

Code Examples

// Step 1: Create your BroadcastReceiver class
class BatteryReceiver : BroadcastReceiver() {

    @Override
    override fun onReceive(context: Context, intent: Intent) {
        when (intent.action) {
            Intent.ACTION_BATTERY_LOW -> {
                // Battery is critically low — take action
                showLowBatteryNotification(context)
            }
            Intent.ACTION_BATTERY_OKAY -> {
                // Battery recovered — clear alerts
                clearNotification(context)
            }
        }
    }

    private fun showLowBatteryNotification(context: Context) {
        // Build and show notification...
        val msg = "⚡ Battery is critically low!"
        Toast.makeText(context, msg, Toast.LENGTH_LONG).show()
    }
}
<!-- AndroidManifest.xml — Static Registration -->
<manifest>

    <application>

        <!-- Declare the receiver component -->
        <receiver
            android:name=".BatteryReceiver"
            android:exported="false">

            <intent-filter>
                <!-- Listen for battery events -->
                <action android:name="android.intent.action.BATTERY_LOW" />
                <action android:name="android.intent.action.BATTERY_OKAY" />
            </intent-filter>

        </receiver>

    </application>

</manifest>

<!-- Note: Many implicit broadcasts can NO LONGER be registered  -->
<!-- in the manifest as of Android 8.0 (API 26) — use Context     -->
<!-- registration or WorkManager for background tasks instead.    -->
class MainActivity : AppCompatActivity() {

    private lateinit var networkReceiver: NetworkChangeReceiver
    private lateinit var filter: IntentFilter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Create receiver and intent filter
        networkReceiver = NetworkChangeReceiver()
        filter = IntentFilter().apply {
            addAction(ConnectivityManager.CONNECTIVITY_ACTION)
        }
    }

    override fun onResume() {
        super.onResume()
        // ✅ Register when active
        registerReceiver(networkReceiver, filter)
    }

    override fun onPause() {
        super.onPause()
        // ✅ Always unregister to prevent memory leaks!
        unregisterReceiver(networkReceiver)
    }
}

Common System Broadcasts

🔋

Battery Low

ACTION_BATTERY_LOW

Fired when device battery drops to a critically low level. Useful for pausing sync operations.

📶

Connectivity Changed

CONNECTIVITY_ACTION

Network state changed — Wi-Fi connected, disconnected, or mobile data toggled.

🚀

Boot Completed

ACTION_BOOT_COMPLETED

Device has finished booting. Start persistent services or schedule jobs after reboot.

Time Changed

ACTION_TIME_CHANGED

User manually changed device time or date. Useful for calendar and scheduling apps.

📦

Package Installed

ACTION_PACKAGE_ADDED

A new app was installed on the device. Used by launchers and app managers.

🔌

Power Connected

ACTION_POWER_CONNECTED

Device connected to a charger. Ideal trigger for heavy background sync operations.

Receiver Lifecycle

Unlike Activities, a Broadcast Receiver has an extremely simple lifecycle — it exists only for the duration of onReceive().

📡

Broadcast Sent

System or app fires the Intent

🔍

Intent Matched

OS finds registered receivers with matching filter

onReceive()

Your code runs — max 10 seconds on main thread

💤

Receiver Idle

Method returns, receiver is inactive again

⚠️
Important: Do not perform long-running operations inside onReceive(). The system can kill your process once the method returns. For async work, use WorkManager, JobScheduler, or start a foreground Service.

Do's & Don'ts

Always unregister dynamic receivers

Unregister in onPause() or onDestroy() to prevent memory leaks and ghost receivers that silently drain resources.

Use LocalBroadcastManager for in-app signals

When communicating within your app, local broadcasts are faster, safer, and data stays within your process. Prefer it over global broadcasts.

🚫

Don't do heavy work in onReceive()

Network calls, database writes, and file I/O have no place in a receiver. Delegate to WorkManager or a Service immediately and return fast.

🚫

Don't rely on implicit manifest receivers on API 26+

Android 8.0+ restricts background implicit broadcasts. Many system actions can no longer wake static receivers — use dynamic registration or WorkManager constraints.

Set android:exported appropriately

If your receiver isn't meant to receive broadcasts from other apps, set android:exported="false" to prevent unintended external access.

Use permissions for sensitive broadcasts

Protect your custom broadcasts with a permission string to ensure only authorized apps can send or receive your proprietary signals.